package org.chartsy.tworsi;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.util.LinkedHashMap;
import org.chartsy.main.ChartFrame;
import org.chartsy.main.chart.Overlay;
import org.chartsy.main.data.DataItem;
import org.chartsy.main.data.Dataset;
import org.chartsy.main.utils.Range;
import org.chartsy.main.utils.SerialVersion;
import org.openide.nodes.AbstractNode;
/**
*
* @author Viorel
*/
public class TwoRSI extends Overlay
{
private static final long serialVersionUID = SerialVersion.APPVERSION;
private OverlayProperties properties;
private int buyRsiS = 61;
private int sellRsiS = 39;
private int buyRsiQ = 61;
private int sellRsiQ = 39;
public TwoRSI()
{
super();
properties = new OverlayProperties();
}
@Override
public Overlay newInstance()
{
return new TwoRSI();
}
@Override
public String getName()
{
return properties.getLabel();
}
@Override
public String getLabel()
{
return properties.getLabel();
}
@Override
public Color[] getColors()
{
return new Color[0];
}
@Override
public double[] getValues(ChartFrame cf)
{
return new double[0];
}
@Override
public double[] getValues(ChartFrame cf, int i)
{
return new double[0];
}
@Override
public boolean getMarkerVisibility()
{
return false;
}
@Override
public AbstractNode getNode()
{
return new OverlayNode(properties);
}
@Override
public String getPrice()
{
return Dataset.CLOSE;
}
@Override
public LinkedHashMap getHTML(ChartFrame cf, int i)
{
LinkedHashMap ht = new LinkedHashMap();
ht.put(getLabel(), " ");
return ht;
}
@Override
public void paint(Graphics2D g, ChartFrame cf, Rectangle bounds)
{
Dataset buy = visibleDataset(cf, "BUY");
Dataset sell = visibleDataset(cf, "SELL");
if (buy != null && sell != null)
{
double barWidth = cf.getChartProperties().getBarWidth();
Range range = cf.getSplitPanel().getChartPanel().getRange();
for (int i = 0; i < buy.getItemsCount(); i++)
{
double value = 0;
if (buy.getDataItem(i) != null)
{
g.setColor(properties.getBuyColor());
value = buy.getCloseAt(i);
}
if (sell.getDataItem(i) != null)
{
g.setColor(properties.getSellColor());
value = sell.getCloseAt(i);
}
double x = cf.getChartData().getX(i, bounds);
double y = cf.getChartData().getY(value, bounds, range, cf.getChartProperties().getAxisLogarithmicFlag());
Ellipse2D.Double circle = new Ellipse2D.Double(x - barWidth/2, y, barWidth, barWidth);
g.fill(circle);
}
}
}
@Override
public void calculate()
{
double[] price = getDataset().getCloseValues();
int count = price.length;
int sRsiPer = properties.getSlowRsiPeriod(),
qRsiPer = properties.getQuickRsiPeriod();
int sMaPer = properties.getSlowMaPeriod(),
qMaPer = properties.getQuickMaPeriod();
int maxPer = Math.max(Math.max(sRsiPer, qRsiPer), Math.max(sMaPer, sMaPer));
// calculate slow and quick RSI
double[] sRsi = getRsiVector(price, sRsiPer),
qRsi = getRsiVector(price, qRsiPer);
// calculate slow and quick MA
double[] sMa = getMaVector(price, sMaPer),
qMa = getMaVector(price, qMaPer);
boolean[] b01 = new boolean[count],
b02 = new boolean[count],
b03 = new boolean[count],
b04 = new boolean[count],
b05 = new boolean[count],
b06 = new boolean[count];
// calculate buy and sell points for slow RSI
double[] sRSIsf = shift(sRsi, 1);
for (int i = maxPer; i < count; i++)
{
b01[i] = (sRSIsf[i] <= buyRsiS) && (sRsi[i] > buyRsiS) && (price[i] > sMa[i]);
b02[i] = ((sRSIsf[i] >= sellRsiS) && (sRsi[i] < sellRsiS)) || (price[i] < sMa[i]);
}
for (int i = maxPer + 1; i < count - 1; i++)
{
if (b01[i] == false && b02[i] == true)
{
b03[i] = false;
b04[i] = true;
}
else
{
if (b01[i] == true && b02[i] == false)
{
b03[i] = true;
b04[i] = false;
}
else
{
b03[i] = b03[i - 1];
b04[i] = b04[i - 1];
}
}
}
// calculate buy and sell points for quick RSI when slow RSI is in downtrend
double[] qRSIsf = shift(qRsi, 1);
for (int i = maxPer; i < count; i++)
{
b01[i] = (qRSIsf[i] <= buyRsiQ) && (qRsi[i] > buyRsiQ) && (price[i] > qMa[i]) && b04[i];
b02[i] = ((qRSIsf[i] >= sellRsiQ) && (qRsi[i] < sellRsiQ)) || (price[i] < qMa[i]);
}
for (int i = maxPer + 1; i < count - 1; i++)
{
if (b01[i] == false && b02[i] == true)
{
b05[i] = false;
b06[i] = true;
}
else
{
if (b01[i] == true && b02[i] == false)
{
b05[i] = true;
b06[i] = false;
}
else
{
b05[i] = b05[i - 1];
b06[i] = b06[i - 1];
}
}
}
for (int i = maxPer; i < count; i++)
{
// determine the buy signals
b01[i] = (b03[i] && b05[i]) || (b03[i] && b06[i]) || (b04[i] && b05[i]);
// determine the sell signals
b02[i] = (b04[i] && b06[i]);
}
boolean[] buy = filterbuy(b01, b02);
boolean[] sell = filtersell(b01, b02);
Dataset buyD = Dataset.EMPTY(count);
Dataset sellD = Dataset.EMPTY(count);
Dataset initial = getDataset();
for (int i = maxPer; i < initial.getItemsCount(); i++)
{
if (buy[i]) buyD.setDataItem(i, new DataItem(initial.getTimeAt(i), initial.getLowAt(i) * 0.95 ));
if (sell[i]) sellD.setDataItem(i, new DataItem(initial.getTimeAt(i), initial.getHighAt(i) * 1.05));
}
addDataset("BUY", buyD);
addDataset("SELL", sellD);
}
private double[] shift(double[] price, int steps)
{
int count = price.length;
double[] result = new double[count];
for (int i = steps; i < count; i++)
result[i] = price[i - steps];
return result;
}
private static boolean[] filterbuy(boolean[] b1, boolean[] b2)
{
int count = Math.min(b1.length, b2.length);
boolean[] result = new boolean[count];
for (int i = 1; i < count - 1; i++)
{
boolean res = b1[i];
boolean buyFlag = false;
for (int j = i - 1; j >= 0; j--)
{
if (b2[j])
break;
if (b1[j])
{
buyFlag = true;
break;
}
}
if (buyFlag)
res = false;
result[i] = res;
}
return result;
}
private static boolean[] filtersell(boolean[] b1, boolean[] b2)
{
int count = Math.min(b1.length, b2.length);
boolean[] result = new boolean[count];
for (int i = 1; i < count - 1; i++)
{
boolean res = b2[i];
boolean sellFlag = false;
for (int j = i - 1; j >= 0; j--)
{
if (b1[j])
break;
if (b2[j])
{
sellFlag = true;
break;
}
}
if (sellFlag)
res = false;
result[i] = res;
}
return result;
}
private double[] getRsiVector(double[] price, int period)
{
double[] vector = new double[price.length];
for (int i = period; i < price.length; i++)
{
double adva = 0;
double decl = 0;
double currentRSI;
for (int j = 0; j < period; j++)
{
if (price[i-j] > price[i-j-1])
{
adva += price[i-j] - price[i-j-1];
}
else if (price[i-j] < price[i-j-1])
{
decl += price[i-j-1] - price[i-j];
}
}
if (decl == 0)
{
currentRSI = 100000D;
}
else
{
currentRSI = (double) adva/decl + 1;
}
vector[i] = 100 - 100/currentRSI;
}
return vector;
}
private double[] getMaVector(double[] price, int period)
{
double[] vector = new double[price.length];
for (int i = period - 1; i < price.length; i++)
{
double close = 0;
for (int j = 0; j < period; j++)
{
close += price[i - j];
}
close /= (double)period;
vector[i] = close;
}
return vector;
}
}